//===--- Validation.h - Validation / errors for serialization ---*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#ifndef POLARPHP_SERIALIZATION_VALIDATION_H
#define POLARPHP_SERIALIZATION_VALIDATION_H

#include "polarphp/basic/LLVM.h"
#include "polarphp/serialization/SerializationOptions.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"

namespace polar {

class ModuleFile;
enum class ResilienceStrategy : unsigned;

namespace serialization {

/// Describes whether a serialized module can be used by this compiler.
enum class Status {
   /// The module is valid.
      Valid,

   /// The module file format is too old to be used by this version of the
   /// compiler.
      FormatTooOld,

   /// The module file format is too new to be used by this version of the
   /// compiler.
      FormatTooNew,

   /// The module file depends on another module that can't be loaded.
      MissingDependency,

   /// The module file is an overlay for a Clang module, which can't be found.
      MissingUnderlyingModule,

   /// The module file depends on a module that is still being loaded, i.e.
   /// there is a circular dependency.
      CircularDependency,

   /// The module file depends on a bridging header that can't be loaded.
      FailedToLoadBridgingHeader,

   /// The module file is malformed in some way.
      Malformed,

   /// The module documentation file is malformed in some way.
      MalformedDocumentation,

   /// The module file's name does not match the module it is being loaded
   /// into.
      NameMismatch,

   /// The module file was built for a different target platform.
      TargetIncompatible,

   /// The module file was built for a target newer than the current target.
      TargetTooNew
};

/// Returns true if the data looks like it contains a serialized AST.
bool isSerializedAST(StringRef data);

/// \see validateSerializedAst()
struct ValidationInfo {
   StringRef name = {};
   StringRef targetTriple = {};
   StringRef shortVersion = {};
   version::Version compatibilityVersion = {};
   size_t bytes = 0;
   Status status = Status::Malformed;
};

/// A collection of options that can be used to set up a new AST context
/// before it has been created.
///
/// Note that this is intended to be a transient data structure; as such,
/// <strong>none of the string values added to it are copied</strong>.
///
/// \sa validateSerializedAst()
class ExtendedValidationInfo {
   SmallVector<StringRef, 4> ExtraClangImporterOpts;
   StringRef SDKPath;
   struct {
      unsigned ArePrivateImportsEnabled : 1;
      unsigned IsSIB : 1;
      unsigned IsTestable : 1;
      unsigned ResilienceStrategy : 2;
   } Bits;
public:
   ExtendedValidationInfo() : Bits() {}

   StringRef getSDKPath() const { return SDKPath; }
   void setSDKPath(StringRef path) {
      assert(SDKPath.empty());
      SDKPath = path;
   }

   ArrayRef<StringRef> getExtraClangImporterOptions() const {
      return ExtraClangImporterOpts;
   }
   void addExtraClangImporterOption(StringRef option) {
      ExtraClangImporterOpts.push_back(option);
   }

   bool isSIB() const { return Bits.IsSIB; }
   void setIsSIB(bool val) {
      Bits.IsSIB = val;
   }
   bool arePrivateImportsEnabled() { return Bits.ArePrivateImportsEnabled; }
   void setPrivateImportsEnabled(bool enabled) {
      Bits.ArePrivateImportsEnabled = enabled;
   }
   bool isTestable() const { return Bits.IsTestable; }
   void setIsTestable(bool val) {
      Bits.IsTestable = val;
   }
   ResilienceStrategy getResilienceStrategy() const {
      return ResilienceStrategy(Bits.ResilienceStrategy);
   }
   void setResilienceStrategy(ResilienceStrategy resilience) {
      Bits.ResilienceStrategy = unsigned(resilience);
   }
};

/// Returns info about the serialized AST in the given data.
///
/// If the returned status is anything but Status::Valid, the serialized data
/// cannot be loaded by this version of the compiler. If the returned size is
/// non-zero, it's possible to skip over this module's data, in case there is
/// more data in the buffer. The returned name, which may be empty, directly
/// points into the given data buffer.
///
/// Note that this does not actually try to load the module or validate any
/// of its dependencies; it only checks that it /can/ be loaded.
///
/// \param data A buffer containing the serialized AST. Result information
/// refers directly into this buffer.
/// \param[out] extendedInfo If present, will be populated with additional
/// compilation options serialized into the AST at build time that may be
/// necessary to load it properly.
/// \param[out] dependencies If present, will be populated with list of
/// input files the module depends on, if present in INPUT_BLOCK.
//ValidationInfo validateSerializedAst(
//   StringRef data, ExtendedValidationInfo *extendedInfo = nullptr,
//   SmallVectorImpl<SerializationOptions::FileDependency> *dependencies =
//   nullptr);

/// Emit diagnostics explaining a failure to load a serialized AST.
///
/// - \p Ctx is an AST context through which any diagnostics are surfaced.
/// - \p diagLoc is the (possibly invalid) location used in the diagnostics.
/// - \p loadInfo and \p extendedInfo describe the attempt to load an AST
///   (\ref validateSerializedAst). Note that loadInfo.Status must not be
///   Status::Valid.
/// - \p moduleBufferID and \p moduleDocBufferID are the buffer identifiers
///   of the module input and doc input buffers respectively (\ref
///   SerializedModuleLoader::loadAST, \ref ModuleFile::load).
/// - \p loadedModuleFile is an invalid loaded module.
/// - \p ModuleName is the name used to refer to the module in diagnostics.
void diagnoseSerializedAstLoadFailure(
   AstContext &Ctx, SourceLoc diagLoc, const ValidationInfo &loadInfo,
   const ExtendedValidationInfo &extendedInfo, StringRef moduleBufferID,
   StringRef moduleDocBufferID, ModuleFile *loadedModuleFile,
   Identifier ModuleName);

} // end namespace serialization
} // end namespace polar

#endif
